


#ifndef PF_GRAPHICVIEW_H
#define PF_GRAPHICVIEW_H

#include "pf_entitycontainer.h"
#include "lx_Export.h"

#include <stdarg.h>
#include <qmap.h>

#include "lx_define.h"
#include "pf_blocklist.h"
#include "pf_color.h"
#include "pf_keyevent.h"
#include "pf_linepattern.h"
#include "pf_mouseevent.h"
#include "pf_commandevent.h"

class PF_ActionInterface;
//class PF_DimensionData;
//class PF_DimLinearData;
class PF_EventHandler;
class PF_Grid;
class PF_Insert;
class PF_Painter;
class PF_Solid;
class PF_Text;
class PF_Hatch;
class PF_Painter;
class PF_Container;
//class PF_MirrorData;
//class PF_MoveData;
//class PF_MoveRotateData;
//class PF_Rotate2Data;
//class PF_RotateData;
//class PF_ScaleData;
//class PF_BevelData;
//class PF_RoundData;



/**
 * This class is a common GUI interface for the graphic viewer 
 * widget which has to be implementet by real GUI classes such 
 * as the Qt graphical view.
 *
 * Note that this is just an interface used as a slot to 
 * communicate with the LXCAD from a GUI level. 
 */
class LX_EXPORT PF_GraphicView {
public:
    PF_GraphicView();
    virtual ~PF_GraphicView();

	void cleanUp();

    /**
     * @return Pointer to the graphic entity if the entity container
     * connected to this view is a graphic and valid.
     * NULL otherwise.
     */
    PF_Graphic* getGraphic() {
        if (container!=NULL && container->rtti()==LX_Define::EntityGraphic) {
            return (PF_Graphic*)container;
        } else {
            return NULL;
        }
    }

    /**
     * Sets the drawing mode.
     */
    void setDrawingMode(LX_Define::DrawingMode m) {
        drawingMode = m;
    }

    /**
     * @return Current drawing mode.
     */
    LX_Define::DrawingMode getDrawingMode() {
        return drawingMode;
    }
	
    /**
     * Activates or deactivates the delete mode.
     */
    void setDeleteMode(bool m) {
        deleteMode = m;
    }

    /**
     * @reval true Deleting instead of drawing.
	 *        false Normal drawing mode.
     */
    bool getDeleteMode() {
        return deleteMode;
    }

    /** This virtual method must be overwritten to return
      the width of the widget the graphic is shown in */
    virtual int getWidth() = 0;
    /** This virtual method must be overwritten to return
      the height of the widget the graphic is shown in */
    virtual int getHeight() = 0;
    /** This virtual method must be overwritten to redraw
      the widget. */
    virtual void redraw(LX_Define::RedrawMethod method=LX_Define::RedrawAll) = 0;
    /** This virtual method must be overwritten and is then
      called whenever the view changed */
    virtual void adjustOffsetControls() {}
    /** This virtual method must be overwritten and is then
      called whenever the view changed */
    virtual void adjustZoomControls() {}
	
    /**
     * Sets the background color. Note that applying the background
     * color for the widget is up to the implementing class.
     */
    virtual void setBackground(const PF_Color& bg) {
        background = bg;

        // bright background:
        if (bg.red()+bg.green()+bg.blue()>380) {
            foreground = PF_Color(0,0,0);
        } else {
            foreground = PF_Color(255,255,255);
        }
    }
	
	/**
	 * @return Current background color.
	 */
	PF_Color getBackground() {
		return background;
	}
	
	/**
	 * @return Current foreground color.
	 */
	PF_Color getForeground() {
		return foreground;
	}

	/**
	 * Sets the grid color.
	 */
	void setGridColor(const PF_Color& c) {
		gridColor = c;
	}

	/**
	 * Sets the meta grid color.
	 */
	void setMetaGridColor(const PF_Color& c) {
		metaGridColor = c;
	}
	
	/**
	 * Sets the selection color.
	 */
	void setSelectedColor(const PF_Color& c) {
		selectedColor = c;
	}
	
	/**
	 * Sets the highlight color.
	 */
	void setHighlightedColor(const PF_Color& c) {
		highlightedColor = c;
	}

    /**
     * This virtual method can be overwritten to set the mouse
     * cursor to the given type.
     */
    virtual void setMouseCursor(LX_Define::CursorType /*c*/) {}

    void setContainer(PF_Container* container);
	PF_Container* getContainer() {
		return container;
	}
    void setFactor(double f) {
		setFactorX(f);
		setFactorY(f);
	}
    void setFactorX(double f);
    void setFactorY(double f);
    //double getFactorX() {
    //    return factor.x;
    //}
    //double getFactorY() {
    //    return factor.y;
    //}
    PF_Vector getFactor() {
        return factor;
    }
    /**
     * Sets the offset of the graphic.
     */
    void setOffset(int ox, int oy) {
        setOffsetX(ox);
        setOffsetY(oy);
    }
    void setOffsetX(int ox) {
        offsetX = ox;
    }
    void setOffsetY(int oy) {
        offsetY = oy;
    }
    int getOffsetX() {
        return offsetX;
    }
    int getOffsetY() {
        return offsetY;
    }
    void centerOffsetX();
    void centerOffsetY();
    void centerX(double x);
    void centerY(double y);
    /**
     * Sets a fixed border in pixel around the graphic. This border
     * specifies how far the user can scroll outside the graphic
     * area.
     */
    void setBorders(int left, int top, int right, int bottom) {
        borderLeft = left;
        borderTop = top;
        borderRight = right;
        borderBottom = bottom;
    }

    int getBorderLeft() {
        return borderLeft;
    }
    int getBorderTop() {
        return borderTop;
    }
    int getBorderRight() {
        return borderRight;
    }
    int getBorderBottom() {
        return borderBottom;
    }

    void freezeZoom(bool freeze) {
        zoomFrozen=freeze;
    }
    bool isZoomFrozen() {
        return zoomFrozen;
    }

    void setDefaultAction(PF_ActionInterface* action);
    PF_ActionInterface*  getDefaultAction();
    void setCurrentAction(PF_ActionInterface* action);
    PF_ActionInterface* getCurrentAction();
	
    void killSelectActions();
    void killAllActions();

    /**
     * Must be overwritten to emulate a mouse move event with
     * the last known mouse position.
     *
     * @see mx, my
     */
    virtual void emulateMouseMoveEvent() = 0;

    void back();
    void enter();

    void mousePressEvent(PF_MouseEvent* e);
    void mouseReleaseEvent(PF_MouseEvent* e);
    void mouseMoveEvent(PF_MouseEvent* e);
    void mouseLeaveEvent();
    void mouseEnterEvent();
    void keyPressEvent(PF_KeyEvent* e);
    void keyReleaseEvent(PF_KeyEvent* e);
	void commandEvent(PF_CommandEvent* e);
	void enableCoordinateInput();
	void disableCoordinateInput();

    virtual void zoomIn(double f=1.5, const PF_Vector& center=PF_Vector(false));
    virtual void zoomInX(double f=1.5);
    virtual void zoomInY(double f=1.5);
    virtual void zoomOut(double f=1.5, const PF_Vector& center=PF_Vector(false));
    virtual void zoomOutX(double f=1.5);
    virtual void zoomOutY(double f=1.5);
    virtual void zoomAuto(bool axis=true, bool keepAspectRatio=true);
    virtual void zoomAutoY(bool axis=true);
    virtual void zoomPrevious();
	virtual void saveView();
	virtual void restoreView();
    virtual void zoomWindow(PF_Vector v1, PF_Vector v2,
                            bool keepAspectRatio=true);
    //virtual void zoomPan(PF_Vector v1);
    virtual void zoomPan(int dx, int dy);
    virtual void zoomScroll(LX_Define::Direction direction);
    virtual void zoomPage();

    virtual void drawWindow_DEPRECATED(PF_Vector v1, PF_Vector v2);
    virtual void drawLayer1(PF_Painter *painter);
    virtual void drawLayer2(PF_Painter *painter);
    virtual void drawLayer3(PF_Painter *painter);
    virtual void deleteEntity(PF_Entity* e);
    virtual void drawEntity(PF_Painter *painter, PF_Entity* e, double patternOffset=0.0);
    virtual void drawEntity(PF_Entity* e, double patternOffset=0.0);
    virtual void drawEntityPlain(PF_Painter *painter, PF_Entity* e, double patternOffset=0.0);
    virtual void setPenForEntity(PF_Painter *painter, PF_Entity* e );
	

    virtual PF_LinePattern* getPattern(LX_Define::LineType t);

    virtual void drawAbsoluteZero(PF_Painter *painter);
    virtual void drawRelativeZero(PF_Painter *painter);
    virtual void drawPaper(PF_Painter *painter);
    virtual void drawGrid(PF_Painter *painter);
    virtual void drawMetaGrid(PF_Painter *painter);
	virtual void drawOverlay(PF_Painter *painter);	
		
    PF_Grid* getGrid() {
        return grid;
    }
        virtual void updateGridStatusWidget(const QString& /*text*/) {}

    void setDefaultSnapMode(LX_Define::SnapMode sm);
    LX_Define::SnapMode getDefaultSnapMode() {
        return defaultSnapMode;
    }
    void setSnapRestriction(LX_Define::SnapRestriction sr);
    LX_Define::SnapRestriction getSnapRestriction() {
        return defaultSnapRes;
    }

    //void showGrid(bool on) {
    //    gridVisible = on;
    //}
    bool isGridOn();

    PF_Vector toGui(PF_Vector v);
    double toGuiX(double x, bool* visible=NULL);
    double toGuiY(double y);
    double toGuiDX(double d);
    double toGuiDY(double d);

    PF_Vector toGraph(PF_Vector v);
    PF_Vector toGraph(int x, int y);
    double toGraphX(int x);
    double toGraphY(int y);
    double toGraphDX(int d);
    double toGraphDY(int d);

	/**
	 * (Un-)Locks the position of the relative zero.
	 *
	 * @param lock true: lock, false: unlock
	 */
	void lockRelativeZero(bool lock) {
		relativeZeroLocked=lock;
	}

	/**
	 * @return true if the position of the realtive zero point is
	 * locked.
	 */
	bool isRelativeZeroLocked() {
		return relativeZeroLocked;
	}

	/**
	 * @return Relative zero coordinate.
	 */
	PF_Vector getRelativeZero() {
		return relativeZero;
	}

	void setRelativeZero(const PF_Vector& pos);
	void moveRelativeZero(const PF_Vector& pos);

	PF_EventHandler* getEventHandler() {
		return eventHandler;
	}

	/**
	 * Enables or disables print preview.
	 */
	void setPrintPreview(bool pv) {
		printPreview = pv;
	}

	/**
	 * @retval true This is a print preview graphic view.
	 * @retval false Otherwise.
	 */
	bool isPrintPreview() {
		return printPreview;
	}
	
	/**
	 * Enables or disables printing.
	 */
	void setPrinting(bool p) {
		printing = p;
	}

	/**
	 * @retval true This is a a graphic view for printing.
	 * @retval false Otherwise.
	 */
	bool isPrinting() {
		return printing;
	}
	
	/**
	 * @retval true Draft mode is on for this view (all lines with 1 pixel / no style scaling).
	 * @retval false Otherwise.
	 */
	inline bool isDraftMode() {
		return draftMode;
	}

	void setDraftMode(bool dm) {
		draftMode=dm;
	}
	
	virtual PF_Container* getOverlayContainer(LX_Define::OverlayGraphics position);
	
protected:
	
	
    PF_Container* container; // Holds a pointer to all the enties
    PF_EventHandler* eventHandler; 


    int mx;   //!< Last known mouse cursor position
    int my;   //!< Last known mouse cursor position

    /** background color (any color) */
    PF_Color background;
    /** foreground color (black or white) */
    PF_Color foreground;
	/** grid color */
    PF_Color gridColor;
	/** meta grid color */
	PF_Color metaGridColor;
    /** selected color */
    PF_Color selectedColor;
    /** highlighted color */
    PF_Color highlightedColor;
    /** Grid */
    PF_Grid* grid;
    /** 
	 * Current default snap mode for this graphic view. Used for new
	 * actions.
	 */
    LX_Define::SnapMode defaultSnapMode;
    /** 
	 * Current default snap restriction for this graphic view. Used for new
	 * actions.
	 */
    LX_Define::SnapRestriction defaultSnapRes;

    LX_Define::DrawingMode drawingMode;

	/**
	 * Delete mode. If true, all drawing actions will delete in background color
	 * instead.
	 */
	bool deleteMode;

private:
    bool zoomFrozen;
    //bool gridVisible;
	bool draftMode;

    PF_Vector factor;
	int offsetX;
    int offsetY;
    
	PF_Vector previousFactor;
	int previousOffsetX;
    int previousOffsetY;

    int borderLeft;
    int borderTop;
    int borderRight;
    int borderBottom;

	PF_Vector relativeZero;
	bool relativeZeroLocked;
	//! Print preview flag
	bool printPreview;
	//! Active when printing only:
	bool printing;
	
	// Map that will be used for overlaying additional items on top of the main CAD drawing
	QMap<int, PF_Container *> overlayEntities;
	
};

#endif
